﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="SortDialog.xaml.cs" company="GT">
//   Gunther Taborga
// </copyright>
// <summary>
//   Interaction logic for SortDialog.xaml
// </summary>
// --------------------------------------------------------------------------------------------------------------------

// TODO refactored=false
namespace BatchID3.Editor.Dialogs
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.IO;
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;

    using BatchID3.Editor.Extensions;
    using BatchID3.Enumerations;
    using BatchID3.Extensions;
    using BatchID3.Mp3;

    public partial class SortDialog : Window, ISortDialog
    {
        private readonly IMp3FileSystemManager mp3FileSystemManager;

        private readonly IFolderBrowserDialogFactory folderBrowserDialogFactory;

        private readonly IMp3Entity previewMp3Entity;

        private string previousBrowseDirectory = string.Empty;

        public SortDialog()
        {
            this.InitializeComponent();
        }

        public SortDialog(
            IMp3FileSystemManager mp3FileSystemManager, 
            IFolderBrowserDialogFactory folderBrowserDialogFactory,
            IMp3PreviewFactory mp3PreviewFactory, 
            IEnumerable<IMp3Entity> mp3Entities, 
            IEnumerable<TagToken> tagTokens, 
            IEnumerable<TagToken> preSelectedTagTokens, 
            string loadedDirectory, 
            string previousDestinationDirectory)
        {
            this.InitializeComponent();
            this.mp3FileSystemManager = mp3FileSystemManager;
            this.folderBrowserDialogFactory = folderBrowserDialogFactory;
            this.previewMp3Entity = mp3PreviewFactory.GetMp3Preview();
            this.SelectedMp3Files = mp3Entities;
            this.LoadedDirectory = loadedDirectory;
            this.DestinationDirectory = previousDestinationDirectory;

            this.Setup(tagTokens, preSelectedTagTokens);
        }

        public event SortProgressChangedEventHandler SortProgressChanged;

        public string DestinationDirectory
        {
            get
            {
                return this.destinationDirectoryTextbox.Text;
            }

            set
            {
                this.destinationDirectoryTextbox.Text = value;
            }
        }

        public string LoadedDirectory { get; set; }

        public IEnumerable<IMp3Entity> SelectedMp3Files { get; private set; }

        private IEnumerable<TagToken> SelectedTagTokens
        {
            get { return this.tagTokenMultiSelectBox.SelectedTagTokens; }
        }

        private void CancelButtonClick(object sender, RoutedEventArgs e)
        {
            this.CloseDialog(false);
        }

        private void CloseDialog(bool dialogResult = true)
        {
            this.DialogResult = dialogResult;
            this.Close();
        }

        private void DestinationDirectoryTextboxTextChanged(object sender, TextChangedEventArgs e)
        {
            this.SetPreviewLabel();
        }

        private void DisableDestinationDirectory()
        {
            this.findDirectoryButton.IsEnabled = false;
            this.destinationDirectoryTextbox.IsEnabled = false;
        }

        private void EnableDestinationDirectory()
        {
            this.findDirectoryButton.IsEnabled = true;
            this.destinationDirectoryTextbox.IsEnabled = true;
        }

        private void FindDirectoryButtonClick(object sender, RoutedEventArgs e)
        {
            this.ShowFolderBrowserDialog();
        }

        private SortArgument GetSortArguments()
        {
            return new SortArgument(this.SelectedMp3Files, this.SelectedTagTokens, this.destinationDirectoryTextbox.Text);
        }

        private void ListBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            this.SetPreviewLabel();
        }

        private void OkButtonClick(object sender, RoutedEventArgs e)
        {
            this.DestinationDirectory = this.mp3FileSystemManager.FileSystem.GetActualPath(this.destinationDirectoryTextbox.Text);
            this.SortSelectedMp3Files();
            this.CloseDialog();
        }

        private void SetPreviewLabel()
        {
            this.previewLabel.Content = this.mp3FileSystemManager.GetNewDirectoryFromId3(
                this.destinationDirectoryTextbox.Text,
                this.previewMp3Entity,
                this.SelectedTagTokens);
        }

        private void Setup(IEnumerable<TagToken> tagTokens, IEnumerable<TagToken> preSelectedTagTokens)
        {
            this.tagTokenMultiSelectBox.SetTagTokens(tagTokens);
            this.tagTokenMultiSelectBox.SetupSelectedTokens(preSelectedTagTokens);
            this.SetupDestinationDirectory();

            // Set before SelectionChanged handler that way
            // we only modify the label once at load time
            this.SetPreviewLabel();
            this.tagTokenMultiSelectBox.ListBox.SelectionChanged += this.ListBoxSelectionChanged;
        }

        // TODO refactor this shit
        private void SetupDestinationDirectory()
        {
            if (this.DestinationDirectory != null && Directory.Exists(this.DestinationDirectory))
            {
                if (this.DestinationDirectory != this.LoadedDirectory)
                {
                    this.useLoadedDirectoryCheckbox.IsChecked = false;
                }

                this.useLoadedDirectoryCheckbox.IsEnabled = true;
                this.EnableDestinationDirectory();
            }
            else if (this.LoadedDirectory != null && Directory.Exists(this.LoadedDirectory))
            {
                this.DestinationDirectory = this.LoadedDirectory;
                this.useLoadedDirectoryCheckbox.IsChecked = true;
                this.useLoadedDirectoryCheckbox.IsEnabled = true;
                this.DisableDestinationDirectory();
            } 
            else
            {
                this.useLoadedDirectoryCheckbox.IsChecked = false;
                this.useLoadedDirectoryCheckbox.IsEnabled = false;
                this.EnableDestinationDirectory();
            }
        }

        private void ShowFolderBrowserDialog()
        {
            using (var folderBrowserDialog = this.folderBrowserDialogFactory.GetFolderBrowserDialog())
            {
                folderBrowserDialog.Description = Properties.Resources.sort_directory_browse_message;
                folderBrowserDialog.RootFolder = Environment.SpecialFolder.MyComputer;

                if (!string.IsNullOrEmpty(this.previousBrowseDirectory))
                {
                    folderBrowserDialog.SelectedPath = this.previousBrowseDirectory;
                }
                else if (!string.IsNullOrEmpty(this.DestinationDirectory))
                {
                    folderBrowserDialog.SelectedPath = this.DestinationDirectory;
                }
                else if (!string.IsNullOrEmpty(this.LoadedDirectory))
                {
                    folderBrowserDialog.SelectedPath = this.LoadedDirectory;
                }

                if (folderBrowserDialog.ShowDialog(this.GetIWin32Window()) == System.Windows.Forms.DialogResult.OK)
                {
                    this.destinationDirectoryTextbox.Text = this.previousBrowseDirectory = folderBrowserDialog.SelectedPath;
                }
            }
        }

        private void SortSelectedMp3Files()
        {
            var sortWorker = new BackgroundWorker { WorkerReportsProgress = true };
            sortWorker.DoWork += this.SortWorkerDoWork;
            sortWorker.ProgressChanged += this.SortWorkerProgressChanged;
            sortWorker.RunWorkerCompleted += this.SortWorkerRunWorkerCompleted;
            sortWorker.RunWorkerAsync(this.GetSortArguments());
        }

        private void SortWorkerDoWork(object sender, DoWorkEventArgs e)
        {
            var sortWorker = (BackgroundWorker)sender;
            var args = (SortArgument)e.Argument;
            var mp3Entities = args.Mp3Entities.ToList();

            for (var i = 0; i < mp3Entities.Count; i++)
            {
                var mp3 = mp3Entities[i];
                var newFilePath = this.mp3FileSystemManager.SortById3(mp3, args.TagTokens, args.DestinationDirectory);
                sortWorker.ReportProgress(i.PercentOf(mp3Entities.Count), new SortProgressChangedState(mp3, newFilePath));
            }
        }

        private void SortWorkerProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            var sortState = (SortProgressChangedState)e.UserState;
            var fileMovedOutOfScope = true;

            var previousDirectory = this.mp3FileSystemManager.FileSystem.GetDirectoryName(sortState.Mp3Entity.FilePath).ToLower();
            DirectoryInfo newPathParentDirectory = Directory.GetParent(sortState.NewFilePath);

            while (newPathParentDirectory != null && fileMovedOutOfScope)
            {
                if (previousDirectory.Equals(newPathParentDirectory.FullName.ToLower()))
                {
                    fileMovedOutOfScope = false;
                }

                newPathParentDirectory = Directory.GetParent(newPathParentDirectory.FullName);
            }

            sortState.Mp3Entity.FilePath = sortState.NewFilePath;

            this.RaiseProgressChangedEvent(e, sortState, fileMovedOutOfScope);
        }

        private void RaiseProgressChangedEvent(ProgressChangedEventArgs e, SortProgressChangedState sortState, bool fileMovedOutOfScope)
        {
            if (this.SortProgressChanged != null)
            {
                this.SortProgressChanged(this, new SortProgressChangedEventArgs(e.ProgressPercentage, sortState.Mp3Entity, fileMovedOutOfScope));
            }
        }

        private void SortWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (this.SortProgressChanged != null)
            {
                this.SortProgressChanged(this, new SortProgressChangedEventArgs(0));
            }
        }

        private void UseLoadedDirectoryCheckboxClick(object sender, RoutedEventArgs e)
        {
            if (this.useLoadedDirectoryCheckbox.IsChecked == true)
            {
                this.DisableDestinationDirectory();
                this.DestinationDirectory = this.LoadedDirectory;
                this.SetupDestinationDirectory();
            }
            else
            {
                this.EnableDestinationDirectory();
            }
        }
    }
}